TokensController   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 142
dl 0
loc 173
ccs 18
cts 18
cp 1
rs 10
c 0
b 0
f 0
wmc 5

5 Functions

Rating   Name   Duplication   Size   Complexity  
A create 0 29 1
B someProtectedRoute 0 62 1
A findOne 0 21 1
A consume 0 25 1
A revokeAllForUser 0 23 1
1 8
import { Controller, Post, UseGuards, Req, Param, Get } from '@nestjs/common';
2 8
import { TokensService } from './tokens.service';
3 8
import { TokenResponseDto } from './dto/token-response.dto/token-response.dto';
4 8
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
5 8
import { ApiBearerAuth, ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
6 8
import { TokenRevocationResponseDto } from './dto/token-revocation-response.dto/TokenRevocationResponseDto';
7 8
import { TokenGuard } from './guards/token.guard';
8
9
@ApiTags('Tokens')
10
@Controller({ path: 'tokens', version: '1' })
11 8
export class TokensController {
12 11
  constructor(private readonly tokensService: TokensService) {}
13
14
  @Post()
15
  @ApiBearerAuth()
16
  @UseGuards(JwtAuthGuard)
17
  @ApiOperation({
18
    summary: 'Create a new token',
19
    description: 'Creates a new token for the authenticated user with specified parameters',
20
  })
21
  @ApiResponse({
22
    status: 201,
23
    description:
24
      'Maximum number of tokens reached. Please consume an existing token before creating a new one',
25
    type: TokenResponseDto,
26
  })
27
  @ApiResponse({
28
    status: 400,
29
    description: 'Bad Request - Invalid token parameters',
30
  })
31
  @ApiResponse({
32
    status: 401,
33
    description: 'Unauthorized - User not authenticated',
34
  })
35 8
  async create(@Req() req): Promise<TokenResponseDto> {
36 1
    const token = await this.tokensService.create(req.user.githubId);
37
38 1
    return {
39
      token: token.id,
40
      remainingUses: token.remainingUses,
41
      expiresAt: token.expiresAt,
42
    };
43
  }
44
45
  @Post(':id/consume')
46
  @ApiOperation({
47
    summary: 'Consume a token',
48
    description: 'Decrements the remaining uses of a token and returns updated token information',
49
  })
50
  @ApiResponse({
51
    status: 201,
52
    description: 'Token consumed successfully',
53
    type: TokenResponseDto,
54
  })
55
  @ApiResponse({
56
    status: 400,
57
    description: 'Bad Request - Token not found or already expired',
58
  })
59
  @ApiResponse({
60
    status: 403,
61
    description: 'Forbidden - Token has no remaining uses',
62
  })
63 8
  async consume(@Param('id') id: string): Promise<TokenResponseDto> {
64 1
    const token = await this.tokensService.consume(id);
65 1
    return {
66
      token: token.id,
67
      remainingUses: token.remainingUses,
68
      expiresAt: token.expiresAt,
69
    };
70
  }
71
72
  @ApiOperation({
73
    summary: 'Protected route example',
74
    description: 'This route requires a valid API token',
75
  })
76
  @ApiHeader({
77
    name: 'x-api-token',
78
    description: 'API Token for route access',
79
    required: true,
80
    schema: { type: 'string' },
81
  })
82
  @ApiResponse({
83
    status: 200,
84
    description: 'Route accessed successfully',
85
    schema: {
86
      type: 'object',
87
      properties: {
88
        message: { type: 'string', example: 'Access granted' },
89
      },
90
    },
91
  })
92
  @ApiResponse({
93
    status: 401,
94
    description: 'Unauthorized - Invalid or missing token',
95
    schema: {
96
      type: 'object',
97
      properties: {
98
        message: { type: 'string', example: 'Token is required' },
99
        statusCode: { type: 'number', example: 401 },
100
      },
101
    },
102
  })
103
  @UseGuards(TokenGuard)
104
  @Get('protected-route')
105 8
  async someProtectedRoute() {
106 1
    const insights = [
107
      "Believe you can and you're halfway there.",
108
      'The only way to do great work is to love what you do.',
109
      'Success is not the key to happiness. Happiness is the key to success.',
110
      "Your time is limited, don't waste it living someone else's life.",
111
      'The best way to predict the future is to invent it.',
112
      "Don't watch the clock; do what it does. Keep going.",
113
      'Keep your face always toward the sunshine—and shadows will fall behind you.',
114
      'The only limit to our realization of tomorrow is our doubts of today.',
115
      'The future belongs to those who believe in the beauty of their dreams.',
116
      'It does not matter how slowly you go as long as you do not stop.',
117
      'Act as if what you do makes a difference. It does.',
118
      'Success usually comes to those who are too busy to be looking for it.',
119
      "Don't be afraid to give up the good to go for the great.",
120
      'I find that the harder I work, the more luck I seem to have.',
121
      'Success is not in what you have, but who you are.',
122
      'The way to get started is to quit talking and begin doing.',
123
      "Don't let yesterday take up too much of today.",
124
      "You learn more from failure than from success. Don't let it stop you. Failure builds character.",
125
      "It's not whether you get knocked down, it's whether you get up.",
126
      "If you are working on something that you really care about, you don't have to be pushed. The vision pulls you.",
127
    ];
128
129 1
    const randomInsight = insights[Math.floor(Math.random() * insights.length)];
130
131 1
    return {
132
      message: `Access granted! Woho, you have just consumed 1 token! Here's a life insight for you: ${randomInsight}`,
133
    };
134
  }
135
136
  @Get(':id')
137
  @ApiOperation({
138
    summary: 'Get token information',
139
    description: 'Retrieves detailed information about a specific token',
140
  })
141
  @ApiResponse({
142
    status: 200,
143
    description: 'Token information retrieved successfully',
144
    type: TokenResponseDto,
145
  })
146
  @ApiResponse({
147
    status: 404,
148
    description: 'Token not found',
149
  })
150 8
  async findOne(@Param('id') id: string): Promise<TokenResponseDto> {
151 1
    const token = await this.tokensService.findOne(id);
152 1
    return {
153
      token: token.id,
154
      remainingUses: token.remainingUses,
155
      expiresAt: token.expiresAt,
156
    };
157
  }
158
159
  @Post('/revoke/user')
160
  @ApiBearerAuth()
161
  @UseGuards(JwtAuthGuard)
162
  @ApiOperation({
163
    summary: 'Revoke all tokens for a user',
164
    description: 'Revokes all tokens for a specific user',
165
  })
166
  @ApiResponse({
167
    status: 200,
168
    description: 'Tokens revoked successfully',
169
    type: TokenRevocationResponseDto,
170
  })
171
  @ApiResponse({
172
    status: 401,
173
    description: 'Unauthorized - User not authenticated',
174
  })
175 8
  async revokeAllForUser(@Req() req): Promise<TokenRevocationResponseDto> {
176 1
    const result = await this.tokensService.revokeAllForUser(req.user.githubId);
177 1
    return {
178
      success: true,
179
      message: 'All tokens have been revoked successfully',
180
      revokedCount: result.affected, // If you want to include this information
181
    };
182
  }
183
}
184